package com.chiyoyo.rabbitmq.framework.utils;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

import java.lang.annotation.Annotation;
import java.util.Map;

/**
 * @author chil
 * Spring上下文工具类
 */
@Configuration
@Order(1)
public class SpringUtil implements ApplicationContextAware {

    private static ApplicationContext context;

    public SpringUtil(ApplicationContext applicationContext) {
        SpringUtil.context = applicationContext;
    }

    /**
     * Spring在bean初始化后会判断是不是ApplicationContextAware的子类
     * 如果该类是,setApplicationContext()方法,会将容器中ApplicationContext作为参数传入进去
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (SpringUtil.context == null) {
            SpringUtil.context = applicationContext;
        }
    }

    public static void setContext(ApplicationContext applicationContext) {
        if (SpringUtil.context == null) {
            SpringUtil.context = applicationContext;
        }
    }

    public static ApplicationContext getApplicationContext() {
        return context;
    }

    /**
     * 通过Name返回指定的Bean
     */
    public static <T> T getBean(Class<T> beanClass) {
        return context.getBean(beanClass);
    }

    public static <T> T getBean(String name, Class<T> beanClass) {
        return context.getBean(name, beanClass);
    }

    /**
     * 根据给定的注解类型，找到Spring容器中使用该注解的Bean，并返回它们的名称和实例的映射关系。
     *
     * @param annotationType 注解类型，不能为null
     * @return 包含使用给定注解的Bean的名称和实例的映射关系的Map，如果未找到任何Bean，则返回空Map
     * @throws IllegalArgumentException 如果传入的注解类型为null
     */
    public static Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) {
        return context.getBeansWithAnnotation(annotationType);
    }

    /**
     * 根据给定类型获取Spring容器中所有Bean的映射关系
     *
     * @param type Bean的类型
     * @param <T>  Bean的泛型类型
     * @return 包含Bean名称和Bean实例的映射关系Map，如果未找到任何Bean，则返回空Map
     */
    public static <T> Map<String, T> getBeansOfType(Class<T> type) {
        return context.getBeansOfType(type);
    }


    /**
     * 读取#{}和${}值
     *
     * @param elKey        需要读取的EL表达式字符串
     * @param defaultValue 默认值，当EL表达式解析结果为null时返回该值
     * @return 返回EL表达式解析后的值，如果解析失败或结果为null，则返回默认值
     */
    public static String getElValue(String elKey, String defaultValue) {
        return ValidateUtils.getOrDefault(getElValue(elKey), defaultValue);
    }

    /**
     * 读取#{}和${}值
     *
     * @param elKey 待解析的EL表达式字符串
     * @return 返回解析后的EL表达式值，如果解析失败则返回原字符串
     */
    public static String getElValue(String elKey) {
        if (elKey.matches("\\$\\{[^}]+}|#\\{[^}]+}")) {
            elKey = ValidateUtils.extractPropertyName(elKey);
            if (elKey != null) {
                return context.getEnvironment().getProperty(elKey);
            }
        }
        return elKey;
    }

    /**
     * 获取EL表达式的默认值
     *
     * @param expression EL表达式字符串
     * @return 返回EL表达式的默认值，如果表达式中不包含冒号，则返回null
     */
    public static String getElDefaultValue(String expression) {
        String defaultValue = null;
        if (expression.contains(":")) {
            defaultValue = expression.substring(expression.indexOf(":") + 1, expression.indexOf("}"));
        }
        return defaultValue;
    }
}
